package controlleur;

import entities.questionnaire.Questionnaire;
import controlleur.util.JsfUtil;
import controlleur.util.PaginationHelper;
import controlleur.util.UtilDate;
import entities.question.AbstractQuestion;
import entities.questionnaire.TypeQuestionnaire;
import entities.questionnaire.TypeScenario;
import entities.utilisateur.AbstractUtilisateur;
import entities.utilisateur.RepondantAuthentifie;
import entities.utilisateur.Valideur;
import facade.AdministrationFacadeLocal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import services.SrvGestionQuestionnaire;
import services.SrvGestionQuestionnaireLocal;

/**
 * managed bean traitant les entités de questionnaires
 * @author mickael.palanchon
 */
@ManagedBean (name="questionnaireController")
@SessionScoped
public class QuestionnaireController implements Serializable {

    private Questionnaire current;
    private DataModel items = null;
    @EJB
    private AdministrationFacadeLocal ejbFacade;
    
    private PaginationHelper pagination;
    private int selectedItemIndex;

    // liste des questions encore disponibles
    private List<AbstractQuestion> listeQuestionAvailable;

    // question à ajouter
    private AbstractQuestion uneQuestion;
    // question à supprimer
    private AbstractQuestion laQuestion;

    // liste des question du questionnaire
    private DataModel dtmQuestions;
    private List<AbstractQuestion> listeQuestion;


    // liste des questions encore disponibles
    private List<RepondantAuthentifie> listeCibleAvailable;

    // cible à ajouter
    private RepondantAuthentifie uneCible;
    // cible à supprimer
    private RepondantAuthentifie laCible;

    // liste des cibles du questionnaire
    private DataModel dtmCibles;
    private List<RepondantAuthentifie> listeCible;

    // booleen permettant de savoir si on effectue un test ou non
    private Boolean isTest = false;

    @ManagedProperty(value="#{userAuthController}")
    private UserAuthController userAuthController;

    public QuestionnaireController() {
    }

    public Questionnaire getSelected() {
        if (current == null) {
            current = new Questionnaire();
            selectedItemIndex = -1;
        }
        return current;
    }

    public void setSelected(Questionnaire questionnaire){
        current = questionnaire;
    }

    private AdministrationFacadeLocal getFacade() {
        return ejbFacade;
    }

    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(10) {

                @Override
                public int getItemsCount() {
                    return getFacade().findAllQuestionnaire().size();
                }

                @Override
                public DataModel createPageDataModel() {
                    return new ListDataModel(getFacade().findQuestionnaireRange(new int[]{getPageFirstItem(), getPageFirstItem()+getPageSize()}));
                }
            };
        }
        return pagination;
    }

    public String prepareList() {
        recreateModel();
        return "List";
    }

    public String prepareView() {
        current = (Questionnaire)getItems().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        return "View";
    }

    /**
     * prépare une occurence de questionnaire pour une création
     * @return la page de création d'un questionnaire
     */
    public String prepareCreate() {
        recreateModel();
        current = new Questionnaire();
        current.setNom(ResourceBundle.getBundle("/Parametres").getString("CreateQuestionnaireNameDefault"));
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(new Date());
        current.setDateDiffusion(gc);
        gc.roll(GregorianCalendar.DAY_OF_MONTH, true);
        current.setDateCloture(gc);
        // TODO: lien à faire avec l'utilisateur connecté
        current.setCreateur(ejbFacade.findCreateur(userAuthController.getLogin()));
        selectedItemIndex = -1;
        return "ToQuestionnaireCreer";
    }

    // persistence de l'objet courant
    public String create() {
        try {
            if (current.getId() > 0){
                current.setListQuestion(listeQuestion);
                current.setListCible(listeCible);
                update();
            } else {
                current.setDateCreation(Calendar.getInstance());
                getFacade().createQuestionnaire(current);
                // mise à jour de l'id pour pouvoir enregistrer les questions
                current.setId(getFacade().getLastIdQuestionnaire());
                // mise à jour de la relation questionnaire questions et questionnaire
                current.setListQuestion(listeQuestion);
                current.setListCible(listeCible);
                getFacade().editQuestionnaire(current);
                JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Parametres").getString("QuestionnaireCreated"));
//                return prepareCreate();
            }
            return "ToQuestionnaireCreer";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Parametres").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String prepareEdit() {
        current = (Questionnaire)getItems().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        return "Edit";
    }

    public String update() {
        try {
            getFacade().editQuestionnaire(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Parametres").getString("QuestionnaireUpdated"));
            return null;
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Parametres").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        current = (Questionnaire)getItems().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        performDestroy();
        recreateModel();
        return "List";
    }

    public String destroyAndView() {
        performDestroy();
        recreateModel();
        updateCurrentItem();
        if (selectedItemIndex >= 0) {
            return "View";
        } else {
            // all items were removed - go back to list
            recreateModel();
            return "List";
        }
    }

    private void performDestroy() {
        try {
//            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Parametres").getString("QuestionnaireDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Parametres").getString("PersistenceErrorOccured"));
        }
    }

    private void updateCurrentItem() {
        int count = getFacade().countQuestionnaire();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count-1;
            // go to previous page if last page disappeared:
            if (pagination.getPageFirstItem() >= count) {
                pagination.previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            current = getFacade().findQuestionnaireRange(new int[]{selectedItemIndex, selectedItemIndex+1}).get(0);
        }
    }

    public DataModel getItems() {
        if (items == null) {
            items = getPagination().createPageDataModel();
        }
        return items;
    }

    private void recreateModel() {
        items = null;
        setListeQuestionAvailable(null);
        setDtmQuestions(null);
    }

    public String next() {
        getPagination().nextPage();
        recreateModel();
        return "List";
    }

    public String previous() {
        getPagination().previousPage();
        recreateModel();
        return "List";
    }

    public String nextFollow() {
        getPagination().nextPage();
        recreateModel();
        return "ListFollow";
    }

    public String previousFollow() {
        getPagination().previousPage();
        recreateModel();
        return "ListFollow";
    }

    public String valider(){
        current = (Questionnaire)getItems().getRowData();
        getFacade().valider(current, (Valideur)getFacade().findUtilisateur(userAuthController.getSelected().getId()));
//        current = getFacade().findQuestionnaire(current.getId());
        if (current.getDateDiffusion().before(UtilDate.getDateDuJourMax()))
            diffuser();
        update();
        return null;
    }

    public String diffuser(){
        System.out.println(current);
        current = (Questionnaire)getItems().getRowData();
        ejbFacade.diffuser(current);
        update();
        return null;
    }

    public String clore(){
        current = (Questionnaire)getItems().getRowData();
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(new Date());
        current.setDateCloture(gc);
        update();
        return null;
    }

    public String tester(){
        current = (Questionnaire)getItems().getRowData();
        setIsTest(true);
        return "ToQuestionnairePasser";
    }

    public String relancer(){
        current = (Questionnaire)getItems().getRowData();
        ejbFacade.relancerDiffusion(current);
        return null;
    }

    public String finish(){
        return null;
    }

    public String bloquer(){
        current = (Questionnaire)getItems().getRowData();
        current.setQuestionnaireBloque(true);
        update();
        return null;
    }

    public String debloquer(){
        current = (Questionnaire)getItems().getRowData();
        current.setQuestionnaireBloque(false);
        update();
        return null;
    }

    public AbstractQuestion getUneQuestion() {
        return uneQuestion;
    }

    public void setUneQuestion(AbstractQuestion question) {
        this.uneQuestion = question;
    }

    public DataModel getDtmCibles() {
        if (dtmCibles == null)
            dtmCibles = new ListDataModel(new ArrayList<AbstractUtilisateur>());
        return dtmCibles;
    }

    public void setDtmCibles(DataModel dtmCibles) {
        this.dtmCibles = dtmCibles;
    }

    public RepondantAuthentifie getLaCible() {
        return laCible;
    }

    public void setLaCible(RepondantAuthentifie laCible) {
        this.laCible = laCible;
    }

    public List<RepondantAuthentifie> getListeCible() {
        if (listeCible == null){
            listeCible = new ArrayList<RepondantAuthentifie>();
        }
        return listeCible;
    }

    public void setListeCible(List<RepondantAuthentifie> listeCible) {
        this.listeCible = listeCible;
    }

    public RepondantAuthentifie getUneCible() {
        return uneCible;
    }

    public void setUneCible(RepondantAuthentifie uneCible) {
        this.uneCible = uneCible;
    }

    public List<RepondantAuthentifie> getListeCibleAvailable() {
        if (listeCibleAvailable == null){
            listeCibleAvailable = new ArrayList<RepondantAuthentifie>();
            listeCibleAvailable = ejbFacade.findAllRepondant();
        }
        return listeCibleAvailable;
    }

    public void setListeCibleAvailable(List<RepondantAuthentifie> listeCibleAvailable) {
        this.listeCibleAvailable = listeCibleAvailable;
    }

    public SelectItem[] getQuestionsAvailableSelectMany() {
        return JsfUtil.getSelectItems(getListeQuestionAvailable(), false);
    }

    public SelectItem[] getCiblesAvailableSelectMany() {
        return JsfUtil.getSelectItems(getListeCibleAvailable(), false);
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAllQuestionnaire(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAllQuestionnaire(), true);
    }

    public SelectItem[] getScenariAvailableSelectMany() {
        return JsfUtil.getSelectItems(Arrays.asList(TypeScenario.values()), false);
    }

    public SelectItem[] getApparencesAvailableSelectMany() {
        return JsfUtil.getSelectItems(Arrays.asList(getFacade().findAllApparence()), false);
    }

    public SelectItem[] getItemsTypesAvailableSelectMany() {
        return JsfUtil.getSelectItems(Arrays.asList(TypeQuestionnaire.values()), false);
    }

    public SelectItem[] getItemsTypesAvailableSelectOne() {
        return JsfUtil.getSelectItems(Arrays.asList(TypeQuestionnaire.values()), true);
    }

    public Date getDateCloture() {
        return current.getDateCloture().getTime();
    }

    public void setDateCloture(Date dateCloture) {
        Calendar c = new GregorianCalendar();
        c.setTime(dateCloture);
        current.setDateCloture(c);
    }

    public Date getDateDiffusion() {
        return current.getDateDiffusion().getTime();
    }

    public void setDateDiffusion(Date dateDiffusion) {
        Calendar c = new GregorianCalendar();
        c.setTime(dateDiffusion);
        current.setDateDiffusion(c);
    }

    public List<AbstractQuestion> getListeQuestionAvailable() {
        if (listeQuestionAvailable == null){
            listeQuestionAvailable = new ArrayList<AbstractQuestion>();
            listeQuestionAvailable = ejbFacade.findAllQuestion();
        }
        return listeQuestionAvailable;
    }

    public void setListeQuestionAvailable(List<AbstractQuestion> uneListeQuestion) {
        this.listeQuestionAvailable = uneListeQuestion;
    }

    public List<AbstractQuestion> getListeQuestion() {
        if (listeQuestion == null){
            listeQuestion = new ArrayList<AbstractQuestion>();
        }
        return listeQuestion;
    }

    public void setListeQuestion(List<AbstractQuestion> uneListeQuestion) {
        this.listeQuestion = uneListeQuestion;
    }

    public DataModel getDtmQuestions() {
        if (dtmQuestions == null)
            dtmQuestions = new ListDataModel(new ArrayList<AbstractQuestion>());
        return dtmQuestions;
    }

    public void setDtmQuestions(DataModel dtmQuestions) {
        this.dtmQuestions = dtmQuestions;
    }

    public AbstractQuestion getLaQuestion() {
        return laQuestion;
    }

    public void setLaQuestion(AbstractQuestion laQuestion) {
        this.laQuestion = laQuestion;
    }

    public Boolean getIsTest() {
        return isTest;
    }

    public void setIsTest(Boolean isTest) {
        this.isTest = isTest;
    }

    public String ajouterQuestion(){
        getListeQuestion().add(uneQuestion);
        dtmQuestions = new ListDataModel(getListeQuestion());
        getListeQuestionAvailable().remove(uneQuestion);
        return null;
    }

    public String retirerQuestion(){
        getListeQuestionAvailable().add(laQuestion);
        getListeQuestion().remove(laQuestion);
        dtmQuestions = new ListDataModel(getListeQuestion());
        return null;
    }

    public String ajouterCible(){
        getListeCible().add(uneCible);
        dtmCibles = new ListDataModel(getListeCible());
        getListeCibleAvailable().remove(uneCible);
        return null;
    }

    public String retirerCible(){
        getListeCibleAvailable().add(laCible);
        getListeCible().remove(laCible);
        dtmCibles = new ListDataModel(getListeCible());
        return null;
    }

    public int getPercentComplete(){
        current = (Questionnaire)getItems().getRowData();
        int nbTotal = current.getListCible().size();
        long nbReel = 0;
        if (nbTotal > 0)
            nbReel = getFacade().countRepondant(current);
        else
            return 0;
        return Math.round((nbReel * 100 / nbTotal));

    }

    public UserAuthController getUserAuthController() {
        return userAuthController;
    }

    public void setUserAuthController(UserAuthController userAuthController) {
        this.userAuthController = userAuthController;
    }

    @FacesConverter(forClass=Questionnaire.class)
    public static class QuestionnaireControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            QuestionnaireController controller = (QuestionnaireController)facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "questionnaireController");
            return controller.ejbFacade.findQuestionnaire(getKey(value));
        }

        long getKey(String value) {
            long key;
            key = Long.parseLong(value);
            return key;
        }

        String getStringKey(long value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Questionnaire) {
                Questionnaire o = (Questionnaire) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: "+QuestionnaireController.class.getName());
            }
        }

    }    

}
